import React, { useRef, useLayoutEffect, useEffect, useState, FC } from "react";
import store, { RootDispatch, RootState } from "@src/store";
import { useSelector, useDispatch } from "react-redux";
import { Modal, Button, Input, message } from "antd";
import classnames from "classnames";
import * as echarts from "echarts/core";
import Api from "@services/api";

import {
  BarChart,
  ScatterChart,
  CustomChart,
  // 系列类型的定义后缀都为 SeriesOption
  BarSeriesOption,
  LineSeriesOption,
  ScatterSeriesOption,
  CustomSeriesOption,
} from "echarts/charts";
import {
  TitleComponent,
  // 组件类型的定义后缀都为 ComponentOption
  TitleComponentOption,
  TooltipComponent,
  TooltipComponentOption,
  GridComponent,
  GridComponentOption,
  // 数据集组件
  DatasetComponent,
  DatasetComponentOption,
  // 内置数据转换器组件 (filter, sort)
  TransformComponent,
} from "echarts/components";
import { LabelLayout, UniversalTransition } from "echarts/features";
import { CanvasRenderer } from "echarts/renderers";

import birdImg from "@assets/images/bird.png";
import _ from "lodash";
import styles from "./style.module.css";
import "./style.scss";

// 通过 ComposeOption 来组合出一个只有必须组件和图表的 Option 类型
type ECOption = echarts.ComposeOption<
  | BarSeriesOption
  | LineSeriesOption
  | TitleComponentOption
  | TooltipComponentOption
  | GridComponentOption
  | DatasetComponentOption
  | ScatterSeriesOption
  | CustomSeriesOption
>;

// 注册必须的组件
echarts.use([
  TitleComponent,
  TooltipComponent,
  GridComponent,
  DatasetComponent,
  TransformComponent,
  BarChart,
  LabelLayout,
  UniversalTransition,
  CanvasRenderer,
  ScatterChart,
  CustomChart,
]);
let obstacleData: number[][] = initObstacleData();
const initOption: ECOption = {
  xAxis: {
    show: false,
    type: "value",
    min: 0,
    max: 200,
  },
  yAxis: {
    show: false,
    min: 0,
    max: 100,
  },
  grid: {
    top: 0,
    bottom: 0,
    left: 0,
    right: 0,
  },
  backgroundcolor: "trans",
  series: [
    {
      name: "bird",
      type: "scatter",
      symbolSize: 50,
      symbol: `image://${birdImg}`,
      symbolRotate: 0,
      data: [[50, 80]],
      animation: false,
    },
    {
      name: "障碍物",
      type: "custom",
      data: [...obstacleData],
      itemStyle: {
        color: {
          type: "linear",
          x: 0,
          y: 0,
          x2: 1,
          y2: 0,
          colorStops: [
            {
              offset: 0,
              color: "#ddf38c", // 0% 处的颜色
            },
            {
              offset: 1,
              color: "#587d2a", // 100% 处的颜色
            },
          ],
          global: false, // 缺省为 false
        },
        borderWidth: 3,
      },
      renderItem,
    },
  ],
};
let option: ECOption = _.cloneDeep(initOption);
function initObstacleData() {
  // 添加minHeight防止空隙太小
  const minHeight = 20;
  const start = 150;
  // eslint-disable-next-line no-shadow
  const dataArr = [];
  for (let index = 0; index < 50; index += 1) {
    const height = Math.random() * 30 + minHeight;
    const obstacleStart = Math.random() * (90 - minHeight);
    dataArr.push([start + 50 * index, obstacleStart, obstacleStart + height > 100 ? 100 : obstacleStart + height]);
  }
  return dataArr;
}
function renderItem(params, api): any {
  // 获取每个水管主体矩形的起始坐标点
  const start1 = api.coord([api.value(0) - 10, api.value(1)]);
  const start2 = api.coord([api.value(0) - 10, 100]);
  // 获取两个水管头矩形的起始坐标点
  const startHead1 = api.coord([api.value(0) - 12, api.value(1)]);
  const startHead2 = api.coord([api.value(0) - 12, api.value(2) + 8]);
  // 水管头矩形的宽高
  const headSize = api.size([24, 8]);
  // 水管头矩形的宽高
  const rect = api.size([20, api.value(1)]);
  const rect2 = api.size([20, 100 - api.value(2)]);
  // 坐标系配置
  const common = {
    x: params.coordSys.x,
    y: params.coordSys.y,
    width: params.coordSys.width,
    height: params.coordSys.height,
  };
  // 水管形状
  const rectShape = echarts.graphic.clipRectByRect(
    {
      x: start1[0],
      y: start1[1],
      width: rect[0],
      height: rect[1],
    },
    common
  );
  const rectShape2 = echarts.graphic.clipRectByRect(
    {
      x: start2[0],
      y: start2[1],
      width: rect2[0],
      height: rect2[1],
    },
    common
  );

  // 水管头形状
  const rectHeadShape = echarts.graphic.clipRectByRect(
    {
      x: startHead1[0],
      y: startHead1[1],
      width: headSize[0],
      height: headSize[1],
    },
    common
  );

  const rectHeadShape2 = echarts.graphic.clipRectByRect(
    {
      x: startHead2[0],
      y: startHead2[1],
      width: headSize[0],
      height: headSize[1],
    },
    common
  );

  // 返回一个group类，由四个矩形组成
  return {
    type: "group",
    children: [
      {
        type: "rect",
        shape: rectShape,
        style: {
          ...api.style(),
          lineWidth: 1,
          stroke: "#000",
        },
      },
      {
        type: "rect",
        shape: rectShape2,
        style: {
          ...api.style(),
          lineWidth: 1,
          stroke: "#000",
        },
      },
      {
        type: "rect",
        shape: rectHeadShape,
        style: {
          ...api.style(),
          lineWidth: 1,
          stroke: "#000",
        },
      },
      {
        type: "rect",
        shape: rectHeadShape2,
        style: {
          ...api.style(),
          lineWidth: 1,
          stroke: "#000",
        },
      },
    ],
  };
}
let vh = 0;
let upa = 0;
let score = 0;
function loopFly(myChart: echarts.ECharts, endAnimation: (...agr: any[]) => void): NodeJS.Timer {
  // 设置速度和加速度
  const a = 0.03;
  const vw = 0.5;
  const upaD = 0.01;
  return setInterval(() => {
    // 小鸟位置和仰角调整
    if (upa > 0) {
      vh += upa;
      upa = upa - upaD > 0 ? upa - upaD : 0;
    } else {
      vh -= a;
    }
    option.series[0].data[0][1] += vh;
    option.series[0].data[0][0] += vw;
    option.series[0].symbolRotate = option.series[0].symbolRotate ? option.series[0].symbolRotate - 5 : 0;
    const result = judgeCollision(option.series[0].data[0]);
    if (result) {
      console.log("result::", result);
      // 产生碰撞后结束动画
      endAnimation(myChart);
    }
    // 坐标系范围调整
    (option.xAxis as any).min += vw;
    (option.xAxis as any).max += vw;

    myChart.setOption(option);
  }, 25);
}

// centerCoord为散点坐标点
function judgeCollision(centerCoord): boolean {
  if (centerCoord[1] < 0 || centerCoord[1] > 100) {
    return true;
  }
  const coordList = [
    [centerCoord[0] + 15, centerCoord[1] + 1],
    [centerCoord[0] + 15, centerCoord[1] - 1],
  ];

  for (let i = 0; i < 2; i += 1) {
    const coord = coordList[i];
    const index = coord[0] / 50;
    if (index % 1 < 0.6 && obstacleData[Math.floor(index) - 3]) {
      if (obstacleData[Math.floor(index) - 3][1] > coord[1] || obstacleData[Math.floor(index) - 3][2] < coord[1]) {
        return true;
      }
    }
    score = (Math.floor(index) - 2) * 2;
  }
  return false;
}
enum GameStatus {
  Init = "init",
  Over = "over",
  Suspend = "suspend",
  Start = "start",
}
const Flybird: FC = function Flybird() {
  const isLogin = useSelector<RootState, RootState["login.isLogin"]>((state) => state.login.isLogin);
  const userId = useSelector<RootState, RootState["login.userId"]>((state) => state.login.userId);
  const gameEle = useRef<HTMLDivElement>(null);
  const timer = useRef(null);
  const myChart = useRef(null);
  const [gameStatus, setGameStatus] = useState<GameStatus>(GameStatus.Init);
  const [visible, setVisible] = useState<boolean>(false);
  const [confirmLoading, setConfirmLoading] = useState<boolean>(false);
  const [name, setName] = useState<string>("");
  const [rankList, setRankList] = useState<any[]>([]);

  const handleKeyDown = (e) => {
    if (e.code === "Space") {
      e.preventDefault();
      upa = 0.1;
      option.series[0].symbolRotate = 45;
    }
  };
  const gameOver = () => {
    clearInterval(timer.current);
    option.series[0].symbolRotate = 180;
    myChart.current.setOption(option);
    setGameStatus(GameStatus.Over);
    Modal.success({
      title: "GAME OVER",
      content: `恭喜你，最终得分${score}分！！！`,
      okText: "再来一局",
    });
    Api.user.addRecord({ fraction: score }).then(() => {
      store.dispatch.login.fetchTouristInfo();
      getRankList();
    });
  };
  const startGame = () => {
    if (!isLogin) {
      setVisible(true);
      return;
    }
    clearInterval(timer.current);
    if (gameStatus === GameStatus.Init) {
      timer.current = loopFly(myChart.current, gameOver);
      setGameStatus(GameStatus.Start);
    } else if (gameStatus === GameStatus.Start) {
      setGameStatus(GameStatus.Suspend);
    } else {
      if (gameStatus === GameStatus.Over) {
        console.log("over start");
        vh = 0;
        upa = 0;
        score = 0;
        obstacleData = initObstacleData();
        option = _.cloneDeep(initOption);
        option.series[1].data = [...obstacleData];
        myChart.current.clear();
        myChart.current.setOption(option);
      }
      timer.current = loopFly(myChart.current, gameOver);
      setGameStatus(GameStatus.Start);
    }
  };
  useEffect(() => {
    console.log("useEffect");
    getRankList();
    myChart.current = echarts.init(gameEle.current);
    myChart.current.setOption(option);
    document.addEventListener("keydown", handleKeyDown);
    return () => {
      document.removeEventListener("keydown", handleKeyDown);
      clearInterval(timer.current);
    };
  }, []);
  const getRankList = () => {
    Api.user.getRank().then((data: any) => {
      console.log(data);
      const { ranks = [] } = data;
      setRankList(ranks);
    });
  };
  const handleCancel = () => {
    setVisible(false);
  };
  const handleOk = async () => {
    if (!name) {
      message.warning("请输入名称");
      return;
    }
    try {
      setConfirmLoading(true);
      await store.dispatch.login.fetchTouristLogin({ name });
      setConfirmLoading(false);
      setVisible(false);
    } catch (err) {
      setConfirmLoading(false);
    }
  };
  return (
    <div className="flybird-page">
      <div>
        <div className={styles.game} ref={gameEle} />
        <div className={styles.btnWrap}>
          <Button type="primary" size="large" onClick={startGame}>
            {{ init: "开始游戏", over: "开始游戏", start: "暂停游戏", suspend: "继续游戏" }[gameStatus]}
          </Button>
          <p>（点击空格向上飞行）</p>
        </div>
      </div>
      <RankingList isLogin={isLogin} list={rankList} />
      <Modal
        title="给自己起个名字吧"
        visible={visible}
        onOk={handleOk}
        confirmLoading={confirmLoading}
        onCancel={handleCancel}
        okText="确认"
        cancelText="取消"
      >
        <div>
          <Input
            placeholder="给自己起个名字吧"
            size="large"
            value={name}
            onChange={(e) => {
              setName(e.target.value);
            }}
          />
        </div>
      </Modal>
    </div>
  );
};
export default Flybird;
type RankingListProps = {
  isLogin: boolean;
  list: any[];
};
const RankingList: FC<RankingListProps> = function RankingList(props) {
  const { isLogin = false, list = [] } = props;
  const userName = useSelector<RootState, RootState["login.name"]>((state) => state.login.name);
  const rank = useSelector<RootState, RootState["login.rank"]>((state) => state.login.rank);
  const maxFraction = useSelector<RootState, RootState["login.maxFraction"]>((state) => state.login.maxFraction);

  const getRankIcon = (index) => {
    const icons = [
      <i className="iconfont icon-guanjun" key={1} style={{ color: "#FDBB1F" }} />,
      <i className="iconfont icon-yajun" key={2} style={{ color: "#DBA599" }} />,
      <i className="iconfont icon-jijun" key={3} style={{ color: "#E3E3E3" }} />,
    ];
    if (index === 0) {
      return "- -";
    }
    if (index <= 3) {
      return icons[index - 1];
    }
    if (index > 10) {
      return "10+";
    }
    return index;
  };
  return (
    <div className="ranking-list">
      <div className="header">
        <p>
          <i className="iconfont icon-paixingbang" style={{ color: "#d81e06" }} />
        </p>
        <p className="name">名称</p>
        <p className="score">分数</p>
      </div>
      <ul>
        {list.map((item) => (
          <li
            className={classnames({
              "li-guanjun": item.rank === 1,
              "li-yajun": item.rank === 2,
              "li-jijun": item.rank === 3,
            })}
            key={item.id}
          >
            <p>{getRankIcon(item.rank)}</p>
            <p className="name">{item.name}</p>
            <p className="score">{item.maxFraction}</p>
          </li>
        ))}

        {isLogin ? (
          <li className="owner">
            <p>{getRankIcon(rank)}</p>
            <p className="name">{userName}</p>
            <p className="score">{maxFraction}</p>
          </li>
        ) : null}
      </ul>
    </div>
  );
};
